package com.huan.seata.service.impl;

import com.huan.seata.service.BusinessService;
import com.huan.seata.service.OrderService;
import io.seata.core.context.RootContext;
import io.seata.core.exception.TransactionException;
import io.seata.spring.annotation.GlobalTransactional;
import io.seata.tm.api.GlobalTransactionContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * @author huan.fu 2021/9/16 - 下午2:35
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class BusinessServiceImpl implements BusinessService {
    
    private final OrderService orderService;
    private final RestTemplate restTemplate;
    
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void rollbackTx(Integer accountId, Long amount, boolean hasException) {
        System.out.println("createAccountOrder:" + RootContext.getXID());
        // 1、远程扣减账户余额
        boolean debitResult = remoteDebit(accountId, amount);
        
        if (!debitResult) {
            log.info("账户服务响应扣库存失败,此处需要回滚分布式事物.");
            if (RootContext.inGlobalTransaction()) {
                try {
                    GlobalTransactionContext.reload(RootContext.getXID()).rollback();
                } catch (TransactionException e) {
                    log.error("回滚分布式事物出现异常", e);
                }
                return;
            }
        }
        
        // 2、下订单
        orderService.createOrder(accountId, amount);
        
        if (hasException) {
            throw new RuntimeException("发生了异常，分布式事物需要会滚");
        }
    }
    
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void bindAndUnBind(Integer accountId, Long amount) {
        String xid = RootContext.getXID();
        System.out.println("createAccountOrder:" + xid);
        
        // 解除 xid 的绑定
        RootContext.unbind();
        
        // 1、远程扣减账户余额
        boolean debitResult = remoteDebit(accountId, amount);
        
        // 重新绑定 xid
        RootContext.bind(xid);
        
        // 2、下订单
        orderService.createOrder(accountId, amount);
        
        // 抛出异常
        int i = 1 / 0;
    }
    
    private boolean remoteDebit(Integer accountId, Long amount) {
        String url = "http://localhost:50016/account/debit?id=" + accountId + "&amount=" + amount;
        Integer result = restTemplate.getForObject(url, Integer.class);
        log.info("远程扣减库存结果:[{}]", result);
        
        return null != result && result > 5;
    }
}
